using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Configuration;
using System.Data.SqlClient;
using System.Configuration.Provider;
using System.Web.Security;
using Systepic.Projects.ProjectsTableAdapters;

namespace Systepic.Projects
{
	/// <summary>
	/// Concrete implementation of the project provider
	/// using the aspnet db and custom schema.
	/// </summary>
	public class SqlProjectsProvider : ProjectsProvider
	{
		private string connectionString;
		private string applicationName;
		private string description;
		private Guid applicationId;
		private SqlConnection conn;
		private smanage_ProjectsTableAdapter projectsAdapter;

		/// <summary>
		/// Initialization called by the ProjectsService
		/// when this class is instantiated which
		/// gets the application information.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="config"></param>
		public override void Initialize(string name,
			System.Collections.Specialized.NameValueCollection config)
		{
			// Make sure the configuration exists
			if ((config == null) || (config.Count == 0))
				throw new ArgumentNullException(
					"You must supply a valid configuration dictionary.");

			// Check for description
			if (string.IsNullOrEmpty(config["description"]))
			{
				config.Remove("description");
				config.Add("description", "Put a localized description here.");
			}
			this.description = config["description"];
			config.Remove("description");

			// Let ProviderBase perform the basic initialization
			base.Initialize(name, config);

			// Make sure the application name is specified
			if (string.IsNullOrEmpty(config["applicationName"]))
				throw new ArgumentNullException("You must supply a valid application name");
			else
				// Assign it to the class
				this.applicationName = config["applicationName"];

			// Remove so we can validate
			config.Remove("applicationName");

			// Get the connection string name from the 
			// Configuration.
			string connectionStringName = config["connectionStringName"];
			if (String.IsNullOrEmpty(connectionStringName))
				throw new ProviderException(
					"You must specify a connectionStringName attribute.");

			// Get the list of availible connection strings
			ConnectionStringsSection cs =
				(ConnectionStringsSection)
				ConfigurationManager.GetSection("connectionStrings");

			// Make sure the list exists
			if (cs == null)
				throw new ProviderException(
					"An error occurred retrieving the connection strings section.");

			// Make sure the connection string specified
			// exists in the list
			if (cs.ConnectionStrings[connectionStringName] == null)
				throw new ProviderException("The connection string could not be found in the connection strings section.");
			else
				// Set the connection string to the
				// one that matches.
				this.connectionString = cs.ConnectionStrings[connectionStringName].ConnectionString;

			// Make sure the connection string is valid
			if (String.IsNullOrEmpty(this.connectionString))
				throw new ProviderException("The connection string is invalid.");
			config.Remove("connectionStringName");

			//Check to see if unexpected attributes were set in configuration
			if (config.Count > 0)
			{
				string extraAttribute = config.GetKey(0);
				if (!String.IsNullOrEmpty(extraAttribute))
					throw new ProviderException("The following unrecognized attribute was found in " + Name + "'s configuration: '" +
												extraAttribute + "'");
				else
					throw new ProviderException("An unrecognized attribute was found in the provider's configuration.");
			}

			this.conn = new SqlConnection(this.connectionString);
			this.CreateApplication(this.applicationName);
			this.projectsAdapter = new smanage_ProjectsTableAdapter();
			this.projectsAdapter.Connection = this.conn;
		}

		/// <summary>
		/// Called by the ApplicationName mutator and
		/// the initialization method and calls the
		/// CreateApplication stored procedure defined
		/// by the aspnetdb.
		/// </summary>
		/// <param name="applicationName"></param>
		private void CreateApplication(string applicationName)
		{
			// Create the command off the connection
			SqlCommand command = new SqlCommand(
				"aspnet_Applications_CreateApplication", this.conn);
			command.CommandType = System.Data.CommandType.StoredProcedure;
			try
			{
				// Add the param and value
				SqlParameter appParam = command.Parameters.Add(
					"@ApplicationName", System.Data.SqlDbType.NVarChar, 256);
				appParam.Value = applicationName;

				// Add the output param
				SqlParameter guidParam = command.Parameters.Add(
					"@ApplicationId", System.Data.SqlDbType.UniqueIdentifier);
				guidParam.Direction = System.Data.ParameterDirection.Output;

				this.conn.Open();
				command.ExecuteNonQuery();

				// Get the information from the output param
				this.applicationId = (Guid)command.Parameters["@ApplicationId"].Value;

				// Change the object
				this.applicationName = applicationName;
			}
			catch (Exception e)
			{
				throw e;
			}
			finally
			{
				this.conn.Close();
			}
		}

		/// <summary>
		/// Get or set the application name
		/// which defines the application pool
		/// to get project and user information.
		/// </summary>
		public override string ApplicationName
		{
			get { return this.applicationName; }
			set
			{
				this.CreateApplication(value);
			}
		}

		/// <summary>
		/// Gets all of the projects in the 
		/// current application pool.
		/// </summary>
		/// <returns>A collection of projects returned</returns>
		public override Collection<Project> GetAllProjects()
		{
			// Create the list
			Collection<Project> list = new Collection<Project>();
			// Get the projects
			Projects.smanage_ProjectsDataTable table = 
				this.projectsAdapter.GetProjects();

			// Populate the list
			for (int x = 0; x < table.Rows.Count; ++x)
			{
			    Project p = new Project();
			    // Fill the requrieds
			    p.Name = table[x].Name;
			    p.ProjectId = table[x].ProjectId;
			    p.CreationDate = table[x].CreationDate;
			    // Fill in the not requireds
			    if (!table[x].IsStartDateNull())
			        p.StartDate = table[x].StartDate;
			    if (!table[x].IsDescriptionNull())
			        p.Description = table[x].Description;
			    if (!table[x].IsCompletionDateNull())
			        p.CompletionDate = table[x].CompletionDate;
				list.Add(p);
			}
			return list;
		}

		/// <summary>
		/// Gets all of the users in the current
		/// application pool.
		/// </summary>
		/// <returns></returns>
		public override Collection<ProjectsUser> GetUsers()
		{
			Collection<ProjectsUser> users = new Collection<ProjectsUser>();
			try
			{
				SqlCommand command = new SqlCommand(
					"aspnet_UsersInRoles_GetUsersInRoles", this.conn);
				command.CommandType = System.Data.CommandType.StoredProcedure;
				command.Parameters.Add(
					new SqlParameter("@ApplicationName", this.applicationName));
				command.Parameters.Add(
					new SqlParameter("@RoleName", "SManage_User"));
				this.conn.Open();
				SqlDataReader reader = command.ExecuteReader();
				while (reader.Read())
				{
					ProjectsUser user = new ProjectsUser();
					user.UserName = (string)reader["UserName"];
					users.Add(user);
				}
			}
			catch (Exception e) { }
			finally
			{
				this.conn.Close();
			}
			return users;
		}

		/// <summary>
		/// Gets all of the projects a user is assigned
		/// to.
		/// </summary>
		/// <param name="username"></param>
		/// <returns></returns>
		public override Collection<Project> GetProjectsForUser(string username)
		{
			//if (username == null)
			//    return new Collection<Project>();

			// Create the list
			Collection<Project> list = new Collection<Project>();
			// Get the projects
			Projects.smanage_ProjectsDataTable table =
				this.projectsAdapter.GetProjectsForUser(username);

			// Populate the list
			for (int x = 0; x < table.Rows.Count; ++x)
			{
				Project p = new Project();
				// Fill the requrieds
				p.Name = table[x].Name;
				p.ProjectId = table[x].ProjectId;
				p.CreationDate = table[x].CreationDate;
				// Fill in the not requireds
				if (!table[x].IsStartDateNull())
					p.StartDate = table[x].StartDate;
				if (!table[x].IsDescriptionNull())
					p.Description = table[x].Description;
				if (!table[x].IsCompletionDateNull())
					p.CompletionDate = table[x].CompletionDate;
				list.Add(p);
			}
			return list;
		}

		/// <summary>
		/// Adds a new project to the current
		/// application pool
		/// </summary>
		/// <param name="project">The project object
		/// to add to the system.</param>
		/// <param name="status">The status of the
		/// addition.</param>
		/// <returns></returns>
		public override Project CreateProject(Project project, out CreateProjectStatus status)
		{
			// Note: Get the project in the next iteration
			if (this.projectsAdapter.AddProject(
				this.applicationId, project.Name, project.Description,
				DateTime.Now, project.StartDate, project.CompletionDate) > 0)
			{
				status = CreateProjectStatus.Success;
				return project;
			}
			else
			{
				status = CreateProjectStatus.Failed;
				return null;
			}
		}

		public override bool UpdateProject(Project project)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		public override bool DeleteProject(Project project)
		{
			return (this.projectsAdapter.DeleteProject(project.ProjectId) > 0) ?
				true : false;
		}

		public override Collection<ProjectsUser> GetUsersInRole(ProjectUserRole role)
		{
			string roleName;
			switch (role)
			{
				case ProjectUserRole.Admin:
					break;
				case ProjectUserRole.Manager:
					break;
				default:
					break;
			}
			return null;
		}

		public override Project GetProjectById(int projectId)
		{
			// Get the projects
			Projects.smanage_ProjectsDataTable table =
				this.projectsAdapter.GetProjectById(projectId);

			if (table.Rows.Count == 0)
				return null;

			Project p = new Project();
			// Fill the requrieds
			p.Name = table[0].Name;
			p.ProjectId = table[0].ProjectId;
			p.CreationDate = table[0].CreationDate;
			// Fill in the not requireds
			if (!table[0].IsStartDateNull())
				p.StartDate = table[0].StartDate;
			if (!table[0].IsDescriptionNull())
				p.Description = table[0].Description;
			if (!table[0].IsCompletionDateNull())
				p.CompletionDate = table[0].CompletionDate;

			return p;
		}
	}
}
